#include "MoveToFront.h"

MoveToFront::MoveToFront(){
    cout << "Move To Front Module ready" << endl;
    subfijo_cod = ".MTF";
};


string MoveToFront::codificar(string path, unsigned int tam_bloque) {

	Archivo origi(path); origi.abrir();
	Bloque bqOrigi(tam_bloque);

	Archivo cod(path+subfijo_cod); cod.abrir();
	Bloque bqCod(tam_bloque);

	std::vector<unsigned char> v_origi(tam_bloque);
	std::vector<unsigned char> v_cod(tam_bloque);

	while( origi.leerBloque(bqOrigi) )
	{
		memcpy(v_origi.data(), bqOrigi.getData(), v_origi.size());

		v_cod = encode(v_origi);

		bqCod.setData(v_cod.data(), v_cod.size());

		cod.escribirBloque(bqCod);
	}

	bqOrigi.resize(origi.bytesLeidos());
	v_origi.resize(origi.bytesLeidos());
	v_cod.resize(origi.bytesLeidos());

	memcpy(v_origi.data(), bqOrigi.getData(), v_origi.size());

	v_cod = encode(v_origi);

	bqCod.setData(v_cod.data(), v_cod.size());

	cod.escribirBloque(bqCod);

	origi.cerrar();
	cod.cerrar();

	return path+subfijo_cod;
}

string MoveToFront::decodificar(string path, unsigned int tam_bloque){
	
	Archivo origi(path); origi.abrir();
	Bloque bqOrigi(tam_bloque);

	string nombre_decod = path.substr(0, path.size()-subfijo_cod.size());
	Archivo decod(nombre_decod); decod.abrir();
	Bloque bqDecod(tam_bloque);

	Archivo origi(path); origi.abrir();
	Bloque bqOrigi(tam_bloque);

	Archivo decod(path+subfijo_cod); decod.abrir();
	Bloque bqDecod(tam_bloque);

	std::vector<unsigned char> v_origi(tam_bloque);
	std::vector<unsigned char> v_cod(tam_bloque);

	while( origi.leerBloque(bqOrigi) )
	{
		memcpy(v_origi.data(), bqOrigi.getData(), v_origi.size());

		v_cod = decode(v_origi);

		bqDecod.setData(v_cod.data(), v_cod.size());

		decod.escribirBloque(bqDecod);
	}

	bqOrigi.resize(origi.bytesLeidos());
	v_origi.resize(origi.bytesLeidos());
	v_cod.resize(origi.bytesLeidos());

	memcpy(v_origi.data(), bqOrigi.getData(), v_origi.size());

	v_cod = encode(v_origi);

	bqDecod.setData(v_cod.data(), v_cod.size());

	decod.escribirBloque(bqDecod);

	origi.cerrar();
	decod.cerrar();

	return nombre_decod;
}

string MoveToFront::makeDictionary(){
    string res;

    for(int i=0; i < 256; i++){
        res += static_cast<unsigned char>(i);
    }
    return res;
}


std::vector<unsigned char> MoveToFront::encode(std::vector<unsigned char> input){

    string dictionary = makeDictionary();
    std::map<char,int> charAppeared = initializeNewAppearanceMap(dictionary);
    std::vector<unsigned char> res;

    //For every char in input
    for(int i=0; i < input.size(); i++){
        char currentChar = input[i];
        int charPos = 0;

        //We store in charPos the position of the current char in the vector
        while(charPos < dictionary.length()){
            if(currentChar == dictionary[charPos]){
                res.push_back(charPos);
                break;
            }
            else
                charPos++;
        }

        //And then we make a Move To Front or Move To Middle
        dictionary = makeTheMove(dictionary, charPos, charAppeared);
    }
    return res;
}


std::vector<unsigned char> MoveToFront::decode(std::vector<unsigned char> moves){

    string dictionary = makeDictionary();
    std::map<char,int> charAppeared = initializeNewAppearanceMap(dictionary);
    std::vector<unsigned char> res;

    //For each move to do
    for(int i=0; i < moves.size(); i++){
        int charPos = moves[i];

        //We store the corresponding char from the dictionary
        res.push_back(dictionary[charPos]);

        //And then we make a Move To Front or Move To Middle
        dictionary = makeTheMove(dictionary, charPos, charAppeared);
    }
    return res;
}
